package com.mytest.provider.service.controller;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayDataDataserviceBillDownloadurlQueryRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayDataDataserviceBillDownloadurlQueryResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.mytest.common.result.Result;
import com.mytest.common.result.ResultGenerator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;



/**
 * @Author: llq
 * @Date: 2020/4/7
 */
@RestController
@RequestMapping("/zfb/pay")
@Slf4j
public class ZFBPayController {
    @Value("${app.appId}")
    private String APP_ID;
    /**
     * 应用私钥
     */
    @Value("${app.merchantPrivateSign}")
    private String APP_PRIVATE_KEY;
    /**
     * 支付宝公钥
     */
    @Value("${app.aliPublicSign}")
    private String ALIPAY_PUBLIC_KEY;
    /**
     * 跳转地址
     */
    @Value("${app.returnUrl}")
    private String return_url;
    /**
     * 回调地址
     */
    @Value("${app.notifyUrl}")
    private String notify_url;
    /**
     * 签名类型
     */
    @Value("${app.signType}")
    private String SIGN_TYPE;
    /**
     * 编码集
     */
    @Value("${app.charset}")
    private String CHARSET;
    /**
     * 支付宝网关
     */
    @Value("${app.payGateWay}")
    private String PayGateWay;
    /**
     * 返回格式
     */
    @Value("${app.format}")
    private String FORMAT;

    /*@Value("${app.switch}")
    private String flag;*/

    /**
     * 支付
     * @throws AlipayApiException
     */
    @PostMapping("certunified/order/a")
    public void aliPay(HttpServletResponse response) throws Exception {
        //实例化阿里支付（获得初始化的AlipayClient）
        AlipayClient alipayClient = new DefaultAlipayClient(PayGateWay, APP_ID, APP_PRIVATE_KEY, FORMAT, CHARSET, ALIPAY_PUBLIC_KEY, SIGN_TYPE);
        //创建api对应的request
        AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();

        //在公共参数中设置回跳和通知地址
//        alipayRequest.setReturnUrl(return_url);      //网页重定向页面 get  不推荐 不保证一定能通知到
        //支付宝服务器端自动调用页面的链接地址 post  ip地址必须是公网
        //返回参数,其中有签名类型和签名(签名是由支付宝内部使用公钥和发送的数据生成的)
        alipayRequest.setNotifyUrl(notify_url);
        //todo 订单号，后续修改为正式的
        String outTradeNo = "" + System.currentTimeMillis();

        Map<String, Object> maps = new HashMap<>();
        //商户订单号
        maps.put("out_trade_no", outTradeNo);
        //订单金额
        maps.put("total_amount", "0.01");
        //产品名称
        maps.put("subject", "测试");
        //销售产品码 QUICK_WAP_WAY
//        maps.put("product_code", "QUICK_WAP_WAY");
        //该笔订单允许的最晚支付时间 （非必填）
//        maps.put("timeout_express", "3m");
        String postData = JSONObject.toJSONString(maps);
        //填充业务参数 json
        alipayRequest.setBizContent(postData);

        //调用SDK生成表单
        String form = alipayClient.pageExecute(alipayRequest).getBody();

        response.setContentType("text/html;charset=" + CHARSET);
        //直接将完整的表单html输出到页面就可以了，剩下的不用管
        response.getWriter().write(form);
        response.getWriter().flush();
        response.getWriter().close();
    }

    /**
     * 验签
     * @param request
     * @return
     */
    @PostMapping(value = "/ali")
    public String notify(HttpServletRequest request){
        Map requestParams = request.getParameterMap();
        /*String q = "";
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            for (int i = 0; i < values.length; i++) {
                q+=name+"="+values[i]+"&";
            }
        }*/

        System.out.println("支付宝支付结果通知"+requestParams.toString());
//        log.info("requestId:{},function:{},response:{}",requestId,"支付宝支付结果通知",q);
        //获取支付宝POST过来反馈信息 (将异步通知中收到的所有参数都存放到map中)
        Map<String,String> params = new HashMap<>();
        //trade_no	支付宝28位交易号
        //trade_status	交易状态
        //total_amount	订单金额
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }

        //boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
        try {
            //调用SDK验证签名
            //将异步通知里的签名取出与剩下的参数重新生成的签名做比较是否相同
            //不一样说明支付失败,支付过程有问题,原因是只有支付宝内部有公钥
            boolean flag = AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, CHARSET,SIGN_TYPE);
            if(flag){
                // TODO 验签成功后，按照支付结果异步通知中的描述，对支付结果中的业务内容进行二次校验，
                // 校验成功后在response中返回success并继续商户自身业务处理，校验失败返回failure
                if("TRADE_SUCCESS".equals(params.get("trade_status"))){

                    //商户订单号
                    String out_trade_no = params.get("out_trade_no");
                    log.info("打印支付宝回调数据" + out_trade_no);
                    //下面省略修改订单逻辑

                    return "success";
                }else {
                    return "failure";
                }
            }else {
                return "failure";
            }
        } catch (AlipayApiException e) {
            // TODO 验签失败则记录异常日志，并在response中返回failure.
            e.printStackTrace();
            log.error("requestId:{} err",request ,e);
            return "failure";
        }
    }

    /**
     * 交易查询
     */
    @PostMapping(value = "/selectPay/{outTradeNo}")
    public void selectPay(@PathVariable("outTradeNo")String outTradeNo) throws Exception {
        //获得初始化的AlipayClient
        AlipayClient alipayClient = new DefaultAlipayClient(PayGateWay, APP_ID, APP_PRIVATE_KEY, FORMAT, CHARSET, ALIPAY_PUBLIC_KEY, SIGN_TYPE);
        //创建API对应的request类
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        request.setBizContent("{" +
                " \"out_trade_no\":\" "+ outTradeNo + "\"," +
                " }");//设置业务参数
        //通过alipayClient调用API，获得对应的response类
        AlipayTradeQueryResponse response = alipayClient.execute(request);
        /*
        trade_no	    支付宝28位交易号
        out_trade_no	支付时传入的商户订单号
        trade_status	交易当前状态
        */
        System.out.print(response.getBody());
        //根据response中的结果继续业务逻辑处理
    }

    /**
     * 交易退款
     */
    @PostMapping(value = "/refound/{outTradeNo}/{refundAmount}")
    public void refound(@PathVariable("outTradeNo")String outTradeNo,@PathVariable("refundAmount")String refundAmount) throws Exception {
        //获得初始化的AlipayClient
        AlipayClient alipayClient = new DefaultAlipayClient(PayGateWay, APP_ID, APP_PRIVATE_KEY, FORMAT, CHARSET, ALIPAY_PUBLIC_KEY, SIGN_TYPE);
        //创建API对应的request类
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
//        out_trade_no	支付时传入的商户订单号，与trade_no必填一个
//        trade_no	支付时返回的支付宝交易号，与out_trade_no必填一个
//        out_request_no	本次退款请求流水号，部分退款时必传
//        refund_amount	本次退款金额
        String outRequestNo = "orn"+System.currentTimeMillis();
        request.setBizContent("{" +
                " \"out_trade_no\":\" " + outTradeNo + "\"," +
                " \"out_request_no\":\"" + outRequestNo + "\"," +
                " \"refund_amount\":\" "+ refundAmount + "\"" +
                " }");//设置业务参数
        //通过alipayClient调用API，获得对应的response类
        AlipayTradeRefundResponse response = alipayClient.execute(request);
        //refund_fee	该笔交易已退款的总金额
        System.out.print(response.getBody());
        //根据response中的结果继续业务逻辑处理
    }


    /**
     * 下载账单文件
     */
    @PostMapping(value = "/download/{billTime}")
    public Result download(@PathVariable("billTime")String billTime) throws Exception {
        Date today = new SimpleDateFormat("yyyy-MM-dd").parse(new Date().toString());
        Date billDay = new SimpleDateFormat("yyyy-MM-dd").parse(billTime);
        if (today.before(billDay)){
            return ResultGenerator.genFailResult("请下载正确的日期账单文件");
        }

        //获得初始化的AlipayClient
        AlipayClient alipayClient = new DefaultAlipayClient(PayGateWay, APP_ID, APP_PRIVATE_KEY, FORMAT, CHARSET, ALIPAY_PUBLIC_KEY, SIGN_TYPE);
        //创建API对应的request类
        AlipayDataDataserviceBillDownloadurlQueryRequest request = new AlipayDataDataserviceBillDownloadurlQueryRequest();
//        bill_type	固定传入trade
//        bill_date	需要下载的账单日期，最晚是当期日期的前一天  e.g: 2016-04-05
        request.setBizContent("{" +
                        " \"bill_type\":\"trade\"," +
                        " \"bill_date\":\"" + billTime + "\"" +
                " }");//设置业务参数
        AlipayDataDataserviceBillDownloadurlQueryResponse response = alipayClient.execute(request);
//        bill_download_url	账单文件下载地址，30秒有效
        System.out.print(response.getBody());
//根据response中的结果继续业务逻辑处理


        // todo 将接口返回的对账单下载地址传入urlStr
        String urlStr = "bill_download_url";
        // todo 指定希望保存的文件路径
        String filePath = "/Users/fund_bill_20160405.csv";
        URL url = null;
        HttpURLConnection httpUrlConnection = null;
        InputStream fis = null;
        FileOutputStream fos = null;
        try {
            url = new URL(urlStr);
            httpUrlConnection = (HttpURLConnection) url.openConnection();
            httpUrlConnection.setConnectTimeout(5 * 1000);
            httpUrlConnection.setDoInput(true);
            httpUrlConnection.setDoOutput(true);
            httpUrlConnection.setUseCaches(false);
            httpUrlConnection.setRequestMethod("GET");
            httpUrlConnection.setRequestProperty("Charsert", "UTF-8");
            httpUrlConnection.connect();
            fis = httpUrlConnection.getInputStream();
            byte[] temp = new byte[1024];
            int b;
            fos = new FileOutputStream(new File(filePath));
            while ((b = fis.read(temp)) != -1) {
                fos.write(temp, 0, b);
                fos.flush();
            }
        } catch (
                MalformedURLException e) {
            e.printStackTrace();
        } catch (
                IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fis != null) fis.close();
                if (fos != null) fos.close();
                if (httpUrlConnection != null) httpUrlConnection.disconnect();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return ResultGenerator.genSuccessResult();
    }

}
